#pragma once

#include "actor.h"
#include "factory.h"

class TestLifecycle
{
	class MyReplica
	{
	public:
		MyReplica ( int attrValue = 0 )
		: attrValue ( attrValue )
		{
		}
		int attrValue;
	};
	class MyActor
	: public Actor < MyActor, MyReplica >
	, public MyReplica
	{
		virtual void UpdateReplica ( MyReplica & replica ) const
		{
			replica = * this;
		}
	public:
		MyActor ( int attrValue )
		: MyReplica ( attrValue )
		{
			TestLifecycle::actorsCreated++;
		}
		virtual ~MyActor ()
		{
			TestLifecycle::actorsDeleted++;
		}
	};
	
	class MyActorsFactory
	: public ActorsFactory < MyActor, MyReplica >
	{
	public:
		MyActorsFactory ( int poolSize = 100 )
		: ActorsFactory < MyActor, MyReplica > ( poolSize )
		{
		}
		Id Create ( int attrValue = 0 )
		{
			return RegisterNewActor ( new MyActor ( attrValue ) );
		}
	};
	
	static void TestCreateActor ()
	{
		MyActorsFactory myFactory;
		MyActorsFactory::Id myActorId = myFactory.Create ( 12345 );
		const MyReplica * myActor = myActorId.GetReplica ();
		assert ( myActor );
		assert ( myActor->attrValue == 12345 );
		assert ( myFactory.InstancesCount () == 1 );
	}
	
	static void TestGetUnregisteredActor ()
	{
		MyActorsFactory myFactory;
		MyActorsFactory::Id id;
		assert ( id.GetReplica () == 0 );
		assert ( myFactory.InstancesCount () == 0 );
	}
	
	static void TestDeleteActor ()
	{
		MyActorsFactory factory;
		MyActorsFactory::Id id1 = factory.Create ();
		MyActorsFactory::Id id2 = factory.Create ();
		id1.Delete ();
		assert ( id1.GetReplica () == 0 );
		assert ( id2.GetReplica () );
		assert ( factory.InstancesCount () == 1 );
		id2.Delete ();
		assert ( id1.GetReplica () == 0 );
		assert ( id2.GetReplica () == 0 );
		assert ( factory.InstancesCount () == 0 );
	}
	
	static void TestReturnToPoolIdAfterDelete ()
	{
		MyActorsFactory factory ( 100 );
		for ( int i = 0; i < 1000; i++ )
			factory.Create ().Delete ();
	}
	
	static void TestDeleteNotExistingId ()
	{
		MyActorsFactory factory;
		MyActorsFactory::Id id = factory.Create ();
		id.Delete ();
		id.Delete ();
		assert ( factory.InstancesCount () == 0 );
	}
	
	static void TestCreateLifetime ()
	{
		actorsCreated = 0;
		MyActorsFactory factory;
		factory.Create ();
		assert ( actorsCreated == 1 );
	}
	
	static void TestDeleteLifetime ()
	{
		actorsDeleted = 0;
		MyActorsFactory factory;
		factory.Create ().Delete ();
		assert ( actorsDeleted == 1 );
	}
	
	static void TestDeleteActorsAfterFactoryDestruction ()
	{
		actorsDeleted = 0;
		{
			MyActorsFactory factory;
			factory.Create ();
		}
		assert ( actorsDeleted == 1 );
	}
	
	static void TestIdCopy ()
	{
		MyActorsFactory factory;
		MyActorsFactory::Id id = factory.Create ();
		MyActorsFactory::Id idCopyByConstructor ( id );
		assert ( id.GetReplica () == idCopyByConstructor.GetReplica () );
		MyActorsFactory::Id idCopyByOperatorEqual;
		idCopyByOperatorEqual = id;
		assert ( id.GetReplica () == idCopyByOperatorEqual.GetReplica () );
	}
	
public:
	static void Run ()
	{
		TestCreateActor ();
		TestGetUnregisteredActor ();
		TestDeleteActor ();
		TestReturnToPoolIdAfterDelete ();
		TestDeleteNotExistingId ();
		TestCreateLifetime ();
		TestDeleteLifetime ();
		TestDeleteActorsAfterFactoryDestruction ();
		TestIdCopy ();
	}
	static int actorsCreated;
	static int actorsDeleted;
};
int TestLifecycle::actorsCreated = 0;
int TestLifecycle::actorsDeleted = 0;
